package com.jeasonzhao.web;

import javax.servlet.jsp.tagext.BodyTagSupport;
import javax.servlet.jsp.tagext.TagSupport;
import com.jeasonzhao.commons.utils.Algorithms;

public abstract class AbstractControlTag extends ControlSupportTag
{
    private static final long serialVersionUID = 1L;
    private String tempHtmlAfterTag = null;
    protected boolean skipBody = false; //Skip body totally?
    private boolean isBodyMethodInvoked = false;
    protected boolean bufferBody = false; //Buffer body?
    protected AbstractControlTag(String strTagName,boolean isSkipBody,boolean isBufferBody)
    {
        super(strTagName);
        this.skipBody = isSkipBody;
        this.bufferBody = isBufferBody;
    }

    protected void beforeTag()
        throws Exception
    {

    }

    protected void afterTag()
        throws Exception
    {
    }

    protected abstract void body(String content)
        throws Exception;

    protected Object prepareData()
        throws Exception
    {
        return null;
    }

    protected void setHTMLAfterTag(String value)
    {
        this.tempHtmlAfterTag = value;
    }

    public final int doStartTag()
    {
//        debug(this.getTagName() +" "+this.getId()+" AbstractControlTag:: doStartTag");
        try
        {
//            debug(this.getTagName() +" "+this.getId()+" AbstractControlTag:: beforeTag");
            Object obj = prepareData();
            if(null != obj)
            {
                this.setEmbeddedData(obj);
            }
            beforeTag();
            writeTagBeginText();
        }
        catch(Exception ex)
        {
//            ex.printStackTrace();
            reset();
            this.write(ServletHelper.exception2HTML(ex,this.getClass()));
            return TagSupport.SKIP_BODY;
        }
        //Check bodycontent, by default, if no content set, the doAfterTag will be skip
        isBodyMethodInvoked = false;
        return skipBody ? TagSupport.SKIP_BODY
            : (bufferBody ? BodyTagSupport.EVAL_BODY_BUFFERED : TagSupport.EVAL_BODY_INCLUDE);
    }

    public final int doAfterBody()
    {
        isBodyMethodInvoked = true;
//        debug(this.getTagName() +" "+this.getId()+" AbstractControlTag:: doAfterBody");
        if(bufferBody)
        {
            try
            {
                this.isUsingBodyWriter = true;
                String strBody = null != this.getBodyContent() ? this.getBodyContent().getString() : null;
//                debug(this.getTagName() +" "+this.getId()+" AbstractControlTag:: doAfterBody::body");
                body(strBody);
            }
            catch(Exception ex)
            {
                ex.printStackTrace();
                this.write(ServletHelper.exception2HTML(ex,this.getClass()));
            }
        }
        return TagSupport.EVAL_PAGE;
    }

    public final int doEndTag()
    {
//        debug(this.getTagName() +" "+this.getId()+" AbstractControlTag:: doEndTag");
        try
        {
            //Check bodycontent, by default, if no content set, the doAfterTag will be skip
            if(isBodyMethodInvoked == false ||
               (this.isUsingBodyWriter == false && (skipBody == true || bufferBody == false)))
            {
                this.isUsingBodyWriter = false;
//                debug(this.getTagName() +" "+this.getId()+" AbstractControlTag:: doEndTag::body");
                body(null);
            }
            writeTagEndText();
//            debug(this.getTagName() +" "+this.getId()+" AbstractControlTag:: afterTag");
            afterTag();
            if(Algorithms.notEmpty(this.tempHtmlAfterTag))
            {
                write(this.tempHtmlAfterTag);
            }

        }
        catch(Exception ex)
        {
            ex.printStackTrace();
            this.write(ServletHelper.exception2HTML(ex,this.getClass()));
        }
        finally
        {
            reset();
        }
        return TagSupport.EVAL_PAGE;
    }

    private void reset()
    {
        this.isUsingBodyWriter = false;
        this.tempHtmlAfterTag = null;
        this.isBodyMethodInvoked = false;
        this.setId(null);
        this.clearAttributes();
        this.cleanEmbeddedData();
    }
}
